package yxy.cherry.battle;

import yxy.cherry.battle.module.*;
import yxy.cherry.battle.module.actor.Actor;
import yxy.cherry.battle.module.affix.Affix;
import yxy.cherry.battle.module.affix.AffixContext.AffixAction;
import yxy.cherry.battle.module.affix.AffixContext.AffixActionClass;
import yxy.cherry.battle.module.affix.AffixFactory;
import yxy.cherry.battle.module.affix.Buff;
import yxy.cherry.battle.module.affix.Buff.BuffStateType;
import yxy.cherry.battle.module.affix.Skill;
import yxy.cherry.battle.module.anger.Anger;
import yxy.cherry.battle.module.event.FighterEvent;
import yxy.cherry.battle.module.record.FighterPosition;
import yxy.cherry.battle.module.record.Record;
import yxy.cherry.battle.module.record.stream.RecordStream_ACT;
import yxy.cherry.battle.module.record.stream.RecordStream_ANG;
import yxy.cherry.battle.module.record.stream.RecordStream_BFA;
import yxy.cherry.battle.suppression.Suppression;
import yxy.cherry.data.DataCenter;
import yxy.cherry.data.bean.herodata;
import yxy.cherry.data.bean.heroadvanced;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static yxy.cherry.battle.module.affix.Affix.VALUE_比率分母;

/** 上场的武将 */
public class Fighter extends Actor {

	Team team;
	Position position;// 武将站位

	FighterData data;

	PropertyData skillPropertyData = new PropertyData();//技能增加的属性，临时存放

	Map<String, Buff> buffMap = new ConcurrentHashMap<>();// 身上的附加效果

	ArrayList<Skill> skills = new ArrayList<>();
	ArrayList<Skill> skills2 = new ArrayList<>();
	ArrayList<Skill> skills3 = new ArrayList<>();
	ArrayList<Skill> skills4 = new ArrayList<>();


	Anger 怒气;
	long 血量 = 0;

	Set<FighterEvent> events = new HashSet<>();

	/////////////////////////////////////////////////////////////////
	public Fighter() {

	}

	public Fighter(Team team, Position position, FighterData data) {
		this.team = team;
		this.position = position;
		this.data = data;
		this.怒气 = new Anger(data.get怒气上限(), data.get初始怒气(), data.get发怒阈值());
		this.血量 = data.getPropertyData().getValue(PropertyType.P_生命);
	}

	public Fighter(Team team, Position position, FighterData data, long 血量) {
		this.team = team;
		this.position = position;
		this.data = data;
		this.怒气 = new Anger(data.get怒气上限(), data.get初始怒气(), data.get发怒阈值());
		this.血量 = 血量;
	}

	public FighterData getData() {
		return data;
	}

	public void setTeam(Team team) {
		this.team = team;
	}

	public Team getTeam() {
		return team;
	}

	public String getName() {
		return "(" + getFighterPosition().name() + ")" + data.getName();
	}

	public int getDataId() {
		return data.getDataId();
	}

	public Camp get阵营() {
		return data.get阵营();
	}

	public int get等级() {
		return data.get等级();
	}

	public int get星级() {
		return data.get星级();
	}

	/** 战斗力 */
	public long getBattlePower() {
		return data.getPower();
	}

	public Position getPosition() {
		return position;
	}

	public long get血量() {
		return 血量;
	}

	/** 血量万分值 */
	public long get血量万分值() {
		long hpp = 血量 * VALUE_比率分母 / get生命();
		if (血量 > 0 && hpp <= 0) {
			hpp = 1;
		}
		return hpp;
	}

	public Collection<Skill> getSkills() {

		return skills;
	}

	// 属性//////////////////////////////////////////////////////////
	public long get速度() {
		long value = getProperty(PropertyType.P_速度);
		return value;
	}

	public long get攻击() {
		long value = getProperty(PropertyType.P_攻击);
		return value;
	}

	public long get生命() {
		long value = getProperty(PropertyType.P_生命);
		return value;
	}

	public long get防御() {
		long value = getProperty(PropertyType.P_防御);
		return value;
	}

	public long get法防() {
		long value = getProperty(PropertyType.P_法防);
		return value;
	}

	public long get暴击() {
		return getProperty(PropertyType.P_暴击);
	}

	public long get抗暴() {
		return getProperty(PropertyType.P_抗暴);
	}

	public long get暴伤() {
		return getProperty(PropertyType.P_暴伤);
	}

	public long get韧性() {
		return getProperty(PropertyType.P_韧性);
	}

	public long get控制() {
		return getProperty(PropertyType.P_控制);
	}

	public long get抗控() {
		return getProperty(PropertyType.P_抗控);
	}

	public long get命中() {
		return getProperty(PropertyType.P_命中);
	}

	public long get闪避() {
		return getProperty(PropertyType.P_闪避);
	}

	public long get治疗() {
		return getProperty(PropertyType.P_治疗);
	}

	public long get受疗() {
		return getProperty(PropertyType.P_受疗);
	}

	public long get法增() { return getProperty(PropertyType.P_法增); }

	public long get法减() { return getProperty(PropertyType.P_法减); }

	public long get增伤() {
		return getProperty(PropertyType.P_增伤);
	}

	public long get减伤() {
		return getProperty(PropertyType.P_减伤);
	}

	// XX 需优化
	public long getProperty(PropertyType type) {
		PropertyData propertyData = new PropertyData();//克隆的中间属性,用来计算例如武将的最终属性
		propertyData.addAllValue(data.getPropertyData());

		propertyData.addAllValue(skillPropertyData);

		for (Buff buff : buffMap.values()) {
			if (buff.isRunning()) {
				propertyData.addAllValue(buff.getPropertyData());
				buff.getTarget().getData().getPropertyData().addAllValue(buff.getTargetPropertyData());
			}
		}

		return propertyData.getValue(type);
	}

	public Collection<Suppression> get克制效果() {
		return data.get克制效果();
	}

	public boolean is活着() {
		return 血量 > 0;
	}

	public Set<FighterEvent> getEvents() {
		return events;
	}

	// 怒气///////////////////////////////////////////////////////////////
	public void add怒气(int point) {
		怒气.addPoint(point);
	}

	public void initAnger(int point) {
		怒气.resetPoint();
		怒气.addPoint(point);
	}

	public int getAnger() {
		return 怒气.getAngerPoint();
	}

	// 行动///////////////////////////////////////////////////////////////

	public void trigger(TriggerPoint triggerPoint) {
		// 技能触发
		for (Affix skill : getSkills()) {
			if (triggerPoint.equals(skill.getTriggerPoint())) {
				Battle.battleLogger(5,getName()+"触发了技能"+skill.getSkilldata().getCode()+":"+skill.getSkilldata().getName()+":"+skill.getSkilldata().getDescribe()+":"+skill.getSkilldata().getParam().toString());
				skill.active();
			}
		}
		// buff触发
		for (Buff buff : buffMap.values()) {
			if (buff.isRunning()) {
				if (triggerPoint.equals(buff.getTriggerPoint())) {
					Battle.battleLogger(5,getName()+"触发了buff"+buff.getSkilldata().getCode()+buff.getSkilldata().getName()+":"+buff.getSkilldata().getDescribe()+":"+buff.getSkilldata().getParam().toString());
					buff.active();
				}
			}
		}
	}

	@Override
	public boolean canAct() {
		return is活着();
	}

	@Override
	public void doAct() {
		// 流脚本 武将行动
		getRecord().stream(new RecordStream_ACT(this)).record();
		Battle.battleLogger(2,getName()+" 开始行动");

		getAffixContext().reset();
		getAffixContext().get攻击行动().set行动者(this);

		// 行动前
		preAct();

		// 行动中
		inAct();

		// 行动后
		postAct();
	}

	private void preAct() {
		Battle.battleLogger(3,"preAct");
		if(怒气.isAnger()&&!getAffixContext().is跳过怒气技能()){
			Battle.battleLogger(4,"怒攻前");
			trigger(TriggerPoint.怒攻前);
		}
		if(!getAffixContext().is跳过普通技能()){
			Battle.battleLogger(4,"普攻前");
			trigger(TriggerPoint.普攻前);
		}
		Battle.battleLogger(4,"动前");
		trigger(TriggerPoint.动前);
	}

	private void inAct() {
		Battle.battleLogger(3,"inAct");
		if (!is活着()) {
			return;
		}

		if (怒气.isAnger() && !getAffixContext().is跳过怒气技能()) {
			getRecord().step();
			// 释放怒气技能
			handle怒攻();
			initAnger(怒气.getAngerPoint() - 怒气.getAngerTrigger());
			getAffixContext().add怒气变动武将(this);
			handle怒后();
			return;
		}
		if (!getAffixContext().is跳过普通技能()) {
			getRecord().step();
			// 释放普通技能
			handle普攻();
			add怒气(data.get怒气增长值());
			getAffixContext().add怒气变动武将(this);
			if (team.get神兵() != null) {
				team.get神兵().add怒气(data.get怒气增长值());
				getAffixContext().add怒气变动武将(team.get神兵());
			}
			handle普后();
		}

	}

	private void postAct() {
		Battle.battleLogger(3,"postAct");
		// 目标 反击
		AffixAction 追攻 = null;
		for (AffixAction action : getAffixContext().get附加行动List()) {
			if (action.get行动类型().contains(AffixActionClass.追加攻击)) {
				追攻 = action;
				continue;
			}

			if (action.get行动类型().contains(AffixActionClass.反击)) {
				if (action.get行动者().isBuffState(BuffStateType.麻痹状态)//
						|| action.get行动者().isBuffState(BuffStateType.眩晕状态) //
						|| action.get行动者().isBuffState(BuffStateType.混乱状态)) {
					continue;
				}
				if (action.get行动者().is活着()) {
					getRecord().step();
					getAffixContext().set附加行动中(true);
					getAffixContext().set附加行动(action);
					action.get行动者().getEvents().add(FighterEvent.FE_Strick);
					action.get行动者().handle普攻();
				}
			}

		}
		// 追攻
		if (追攻 != null && 追攻.get行动者().is活着()) {
			getRecord().step();
			getAffixContext().set附加行动中(true);
			getAffixContext().set附加行动(追攻);
			追攻.get行动者().handle普攻();
		}

		// 怒气变动
		{
			for (Fighter fighter : getAffixContext().get怒气变动武将()) {
				getRecord().stream(new RecordStream_ANG(fighter)).record();
			}
		}

		// 失效BUFF
		{
			ArrayList<Buff> buffList = new ArrayList<>();
			for (Buff buff : buffMap.values()) {
				if (!buff.isRunning()) {
					buffList.add(removeBuff(buff));
				}
			}
			if (buffList.size() > 0) {
				getRecord().stream(new RecordStream_BFA(this, buffList)).record();
			}
		}

	}

	public void handle普攻() {
		Battle.battleLogger(4,"普攻");
		getAffixContext().get攻击行动().add行动类型(AffixActionClass.普通技能);
		trigger(TriggerPoint.普攻);
	}

	public void handle怒攻() {
		Battle.battleLogger(4,"怒攻");
		getAffixContext().get攻击行动().add行动类型(AffixActionClass.怒气技能);
		trigger(TriggerPoint.怒攻);
	}

	public void handle攻击时() {
		Battle.battleLogger(4,"攻时");
		trigger(TriggerPoint.攻时);
	}

	public void handle怒攻时() {
		Battle.battleLogger(4,"怒攻时");
		trigger(TriggerPoint.怒攻时);
	}

	public void handle普攻时() {
		Battle.battleLogger(4,"普攻时");
		trigger(TriggerPoint.普攻时);
	}

	public void handle治疗() {
		Battle.battleLogger(4,"治疗时");
		trigger(TriggerPoint.治疗时);
	}

	public void handle普后() {
		Battle.battleLogger(4,"普后");
		trigger(TriggerPoint.普后);
		Battle.battleLogger(4,"攻后");
		trigger(TriggerPoint.攻后);
	}

	public void handle怒后() {
		Battle.battleLogger(4,"怒后");
		trigger(TriggerPoint.怒后);
		Battle.battleLogger(4,"攻后");
		trigger(TriggerPoint.攻后);
	}

	// 被动///////////////////////////////////////////////////////////////

	//主要用于援护
	public void handle阵营受攻() {
		for (Fighter fighter : getTeam().getTeam对手().getFighters()) {
			Battle.battleLogger(4,"阵营受攻");
			fighter.trigger(TriggerPoint.阵营受攻);
		}
	}

	public void handle受到攻击时() {
		Battle.battleLogger(4,"受攻");
		trigger(TriggerPoint.受攻);
	}

	public void handle受疗() {
		Battle.battleLogger(4,"受疗");
		trigger(TriggerPoint.受疗);
	}

	public void handle受到攻击后() {
		Battle.battleLogger(4,"受攻后");
		trigger(TriggerPoint.受攻后);
	}

	public void handle对方有死将(){
		Battle.battleLogger(4,"对方有死将");
		for (Fighter fighter : getTeam().getFighters()) {
			fighter.trigger(TriggerPoint.对方有死将);
		}
	}

	public void handle本方有死将() {
		Battle.battleLogger(4,"本方有死将");
		for (Fighter fighter : getTeam().getFighters()) {
			if (!fighter.equals(this)) {
				fighter.trigger(TriggerPoint.本方有死将);
			}
		}
		Battle.battleLogger(4,"死亡时");
		trigger(TriggerPoint.死亡时);
	}

	public void handle复活(long 治疗量) {
		血量 += 治疗量;
		Battle.battleLogger(4,"复活时");
		trigger(TriggerPoint.复活时);
		events.add(FighterEvent.FE_复活过);
	}

	public boolean is复活过() {
		return events.contains(FighterEvent.FE_复活过);
	}

	public void set伤害(long 伤害) {
		血量 -= 伤害;
		if (血量 < 0) {
			血量 = 0;
		}
	}

	public void set治疗(long 治疗) {
		血量 += 治疗;
		if (血量 > get生命()) {
			血量 = get生命();
		}
	}

	// BUFF///////////////////////////////////////////////////////////////
	public Map<String, Buff> getBuffMap() {
		return buffMap;
	}

	public Buff removeBuff(Buff buff) {
		return buffMap.remove(buff.getBuffCodeSeq());
	}

	public boolean isBuffState(BuffStateType stateType) {
		for (Buff buff : buffMap.values()) {
			if (buff.getBuffStateType().equals(stateType)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 获取各种状态数量，例如负面
	 * @return
	 */
	public int getDownSideStateNumber(Buff.BuffType buffType){
		int number = 0;
		for (Buff buff: buffMap.values()){
			if(buff.getBuffType().equals(buffType)){
				number++;
			}
		}
		return number;
	}

	/////////////////////////////////////////////////////////////////
	protected FighterPosition fighterPosition;// 全局位置参

	public void setFighterPosition(boolean isLeft) {
		if (this.fighterPosition != null) {
			return;
		}
		fighterPosition = FighterPosition.forPosition(getPosition(), isLeft);
	}

	public FighterPosition getFighterPosition() {
		return fighterPosition;
	}

	@Override
	public void transmitRecord(Record record) {
		for (Affix affix : getSkills()) {
			affix.setRecord(record);
		}
	}

	// 创建///////////////////////////////////////////////////////////////

	public static Fighter createFighter(Team team, Position position, long 实际血量, int heroId, int level, int stage, int starlv, int anger, long power,
			PropertyData propertyData, Collection<String> skills) throws Exception {
		herodata _herodata = DataCenter.getData(heroId, herodata.class);
//		System.err.println("createFighter::" + _herodata.getName());
		if (starlv <= _herodata.getStartcs()) {
			starlv = _herodata.getStartcs();
		}
		heroadvanced _heroadvanced = DataCenter.getData(String.format("%d_%d", heroId, starlv), heroadvanced.class);

		FighterData fighterdata = new FighterData(_herodata, _heroadvanced, level, stage, starlv, anger, power, propertyData, skills);
		Fighter fighter = new Fighter(team, position, fighterdata, 实际血量);

		fighter.skills.addAll(AffixFactory.getInstance().createAffix(fighter, _heroadvanced.getPuanger(), _heroadvanced.level[0], stage));// 普通技
		fighter.skills.addAll(AffixFactory.getInstance().createAffix(fighter, _heroadvanced.getAnger(), _heroadvanced.level[1], stage));// 怒气技
		fighter.skills.addAll(AffixFactory.getInstance().createAffix(fighter, _heroadvanced.getPassive1(), _heroadvanced.level[2], stage));// 附加技1
		fighter.skills.addAll(AffixFactory.getInstance().createAffix(fighter, _heroadvanced.getPassive2(), _heroadvanced.level[3], stage));// 附加技2
		fighter.skills.addAll(AffixFactory.getInstance().createAffix(fighter, _heroadvanced.getPassive3(), _heroadvanced.level[4], stage));// 附加技3

		// 扩展技能
		if (skills != null) {
			for (String skillCode : skills) {
				fighter.skills.addAll(AffixFactory.getInstance().createAffix(fighter, skillCode, 1));
			}
		}
		return fighter;
	}

	@Override
	public String toString() {
		return "(" + getDataId() + ")" + getName();
	}

	/**
	 * 根据属性和比例计算攻击力
	 * @param attribute
	 * @param calPer
	 * @return
	 */
	public long genAttackByAttribute(int attribute, int calPer) {
		if (isRealAttribute(attribute)) {
			long value = getProperty(PropertyType.forNumber(attribute));
			long realAttack = value * calPer/VALUE_比率分母;
			return realAttack;
		}else{
			return 0;
		}
	}

	/**
	 * 判断策划是不是真提供了属性值
	 * @param attribute
	 * @return
	 */
	public boolean isRealAttribute(int attribute){
		if(attribute > 0){
			return true;
		}else{
			return false;
		}
	}
}
